﻿using System.Collections.Generic;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace JTLeigh.Commerce.Spencer.Core.Business.UnitTests
{

    /// <summary>
    /// Unit tests for the <see cref="PaginationTools"/> class.
    /// </summary>
    [TestClass]
    public class PaginationToolsFixture
    {

        #region Methods

        #region Paginate

        /// <summary>
        /// Ensures that <see cref="PaginationTools.Paginate{T}"/> performs correctly when the 
        /// number of items is evenly divisible by the maximum number of items per page, returning
        /// <code>items.Count / maximumItemsPerPage</code> pages.
        /// </summary>
        [TestMethod]
        public void TestPaginateWithEvenlyDivisibleItemCount()
        {
            List<int> items;
            PaginationResult<int> result;

            items = GetTestItems(20); // 20 items

            result = PaginationTools.Paginate<int>(items, 2, 5, 10); // page 2, max 5 pages, max 10 items per page
            Assert.AreEqual(2, result.CurrentPage);
            Assert.AreEqual(10, result.ItemsOnCurrentPage.Count);
            Assert.AreEqual(11, result.ItemsOnCurrentPage[0]);
            Assert.AreEqual(20, result.ItemsOnCurrentPage[9]);
            Assert.AreEqual(2, result.TotalPages);
        }

        /// <summary>
        /// Ensures that <see cref="PaginationTools.Paginate{T}"/> performs correctly when the 
        /// number of items isn't evenly divisible by the maximum number of items per page, 
        /// returning <code>(items.Count / maximumItemsPerPage) + 1</code> pages.
        /// </summary>
        [TestMethod]
        public void TestPaginateWithUnevenlyDivisibleItemCount()
        {
            List<int> items;
            PaginationResult<int> result;

            items = GetTestItems(19); // 19 items

            result = PaginationTools.Paginate<int>(items, 2, 5, 10); // page 2, max 5 pages, max 10 items per page
            Assert.AreEqual(2, result.CurrentPage);
            Assert.AreEqual(9, result.ItemsOnCurrentPage.Count);
            Assert.AreEqual(11, result.ItemsOnCurrentPage[0]);
            Assert.AreEqual(19, result.ItemsOnCurrentPage[8]);
            Assert.AreEqual(2, result.TotalPages);
        }

        /// <summary>
        /// Ensures that <see cref="PaginationTools.Paginate{T}"/> performs correctly when there 
        /// are no items, returning page 1 of 1 with no items.
        /// </summary>
        [TestMethod]
        public void TestPaginateWithNoItems()
        {
            List<int> items;
            PaginationResult<int> result;

            items = GetTestItems(0); // 0 items

            result = PaginationTools.Paginate<int>(items, 1, 5, 10); // page 1, max 5 pages, max 10 items per page
            Assert.AreEqual(1, result.CurrentPage);
            Assert.AreEqual(0, result.ItemsOnCurrentPage.Count);
            Assert.AreEqual(1, result.TotalPages);
        }

        /// <summary>
        /// Ensures that <see cref="PaginationTools.Paginate{T}"/> performs correctly when the 
        /// current page is outside the available page range, returning page n of n.
        /// </summary>
        [TestMethod]
        public void TestPaginateWithCurrentPageOutsidePageRange()
        {
            List<int> items;
            PaginationResult<int> result;

            items = GetTestItems(20); // 20 items

            result = PaginationTools.Paginate<int>(items, 3, 5, 10); // page 3, max 5 pages, max 10 items per page
            Assert.AreEqual(2, result.CurrentPage); // wanted page 3, but there are only 2 pages 
            Assert.AreEqual(10, result.ItemsOnCurrentPage.Count);
            Assert.AreEqual(11, result.ItemsOnCurrentPage[0]);
            Assert.AreEqual(20, result.ItemsOnCurrentPage[9]);
            Assert.AreEqual(2, result.TotalPages);
        }

        /// <summary>
        /// Ensures that <see cref="PaginationTools.Paginate{T}"/> performs correctly when the list
        /// of items contain more items than can be paginated, returning the maximum number of 
        /// pages.
        /// </summary>
        [TestMethod]
        public void TestPaginateWithMoreItemsThanCanBePaginated()
        {
            List<int> items;
            PaginationResult<int> result;

            items = GetTestItems(100); // 100 items

            result = PaginationTools.Paginate<int>(items, 1, 5, 10); // page 1, max 5 pages, max 10 items per page
            Assert.AreEqual(1, result.CurrentPage);
            Assert.AreEqual(10, result.ItemsOnCurrentPage.Count);
            Assert.AreEqual(1, result.ItemsOnCurrentPage[0]);
            Assert.AreEqual(10, result.ItemsOnCurrentPage[9]);
            Assert.AreEqual(5, result.TotalPages);
        }

        #endregion // Paginate

        #endregion // Methods

        #region Implementation

        private static List<int> GetTestItems(int itemCount)
        {
            List<int> items;

            items = new List<int>(itemCount);
            for (int i = 1; i <= itemCount; i++)
            {
                items.Add(i);
            }
            return items;
        }

        #endregion // Implementation

    }

}
